#!/usr/bin/env python
"""
Module for basic Shadowrun utilities.

Code license:

The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
License for the specific language governing rights and limitations under 
the License.

The Original Code is copyright 2009 OCSrun.

The Initial Developer of the Original Code is OCSrun. All Rights Reserved.

Contributor(s): Brian C. Young.


Content license: Copyright 2001-2008 WizKids, Inc.

WizKids, Inc. has sole ownership of the names, logo, artwork, marks,
photographs, sounds, audio, video and/or any proprietary material used in
connection with the game Shadowrun. WizKids, Inc. has granted permission to
OCSrun to use such names, logos, artwork, marks and/or any proprietary
materials for promotional and informational purposes on its website but does
not endorse, and is not affiliated with OCSrun in any official capacity
whatsoever.
"""

from random import randint

def rollDice(n, edge = False, verbose = False):
    """
    Rolls n dice and returns a tuple containing the number of hits, a
    boolean indicating a glitch, and a boolean indicating a critical
    glitch.
    """
    if n <= 0:
        return (0, False, False)
    glitch = False
    crit = False
    hits = 0
    ones = 0
    i = 0
    rolls = []
    while i < n:
        i += 1
        roll = randint(1, 6)
        rolls.append(roll)
        if roll == 1:
            ones += 1
        if roll >= 5:
            hits += 1
        if roll == 6 and edge:
            i -= 1

    if ones >= n / 2.0:
        glitch = True
        if hits == 0:
            crit = True
    if verbose:
        rolls.sort()
        print rolls

    return (hits, glitch, crit)

###########
# Tkinter GUI
###########

from Tkinter import *

def stringCouldBecomeInt(text):
    """
    Check if a string either can be cast to an int, or could be cast to
    an int if more characters were added. Used as a validation function
    for number-entry text boxes.
    """
    if text == "" or text == "-":
        return True
    try:
        val = int(text)
        return True
    except ValueError:
        return False

class ValidatingIntVar(StringVar):
    """
    Takes string input, and safely casts to integer on get(). If it's
    not an integer, returns zero.
    """
    def get(self):
        """
        Return the value of the variable as an integer.
        """
        text = StringVar.get(self)
        try:
            return int(text)
        except ValueError:
            return 0

class LabeledNumberEntry (Frame):
    """
    A Tkinter composite class with a label and a Spinbox, that tries to
    keep entries limited to numbers in a certain range.
    """
    def __init__(self, master, text, width, var, from_, to,
                 cb, horizontal):
        """
        Constructor. Arguments (all required):
            master - Widget - parent Tkinter widget
            text - string - to put in the label
            width - int - width to make the label
            var - ValidatingIntVar (please) - will receive changes
            from_ - int - minimum value
            to - int - maximum value
            cb - function(string, string, string) - callback for when the
                value changes. First arg is the name of the variable
                changing, second arg is an index (of what I don't know),
                third args is the change mode (will be 'w')
            horizontal - boolean - True will have the label next to the
                Spinbox, False will have it on top
        """
        Frame.__init__(self, master, padx=2)
        if (horizontal):
            side=LEFT
        else:
            side=TOP
        Label(self, text=text, width=width).pack(side=side)
        var.trace("w", cb)
        self.sb = Spinbox(self, from_=from_, to=to, width=3,
                          validate="key", textvariable = var)
        self.sb.config(vcmd=(self.sb.register(stringCouldBecomeInt), "%P"))
        self.sb.pack(side=side)

    def setEnabled(self, enabled):
        """
        Set the editable state of the contained spinbox.
        """
        if enabled:
            self.sb.config(state=NORMAL)
        else:
            self.sb.config(state=DISABLED)

def showAboutWindow(parent):
    """
    Open a new Tkinter window with program information, copyright,
    etcetera.
    """

    abouttext = """Shadowrun Fourth Edition Python tools
Developed by OCSrun

WizKids, Inc. has sole ownership of the names, logo, artwork, marks,
photographs, sounds, audio, video and/or any proprietary material used in
connection with the game Shadowrun. WizKids, Inc. has granted permission to
OCSrun to use such names, logos, artwork, marks and/or any proprietary
materials for promotional and informational purposes on its website but does
not endorse, and is not affiliated with OCSrun in any official capacity."""
    
    dialog = Toplevel()
    dialog.wm_resizable(False, False)
    dialog.wm_title("About")
    Label(dialog, text=abouttext).pack()
    Button(dialog, text="OK", width=8, command=dialog.destroy).pack()
    #dialog.transient(parent)
    dialog.focus_set()
    dialog.grab_set()
    

# Module tests
if __name__ == "__main__":
    print "Dice tests"
    
    for dice in range(1,8):
        for test in range(1,4):
            (hits, glitch, crit) = rollDice(dice, test == 3, True)
            print "Rolled", dice, "dice,", hits, "hits,", \
                  glitch, "glitch,", crit, "critical"
